import { logMgr } from "./LogMgr"

interface AssetObj {
    asset: cc.Asset,
    decRef: number,
    lock: number,
    fun: Function[]
}

class ResMgr {

    public static instance: ResMgr = null
    public static getInstance() {
        if (!ResMgr.instance) {
            ResMgr.instance = new ResMgr()
        }
        return ResMgr.instance
    }
    private cache: Map<string, AssetObj> = new Map<string, AssetObj>()

    /**
     * 加载asset资源
     * @param assetPath  resource资源路径
     * @param type 资源类型
     * @returns cc.Asset
     */
    async load<T extends cc.Asset>(assetPath: string, type: typeof cc.Asset): Promise<T> {
        let assetObj = this.cache.get(assetPath)
        if (!assetObj) {
            assetObj = {
                asset: null,
                decRef: 0,
                lock: 0,
                fun: []
            }
            this.cache.set(assetPath, assetObj)
        }
        assetObj.lock += 1
        return new Promise((resolve, reject) => {
            if (assetObj.asset) {
                assetObj.asset.addRef()
                resolve(assetObj.asset as T)
                assetObj.lock -= 1
                return
            }
            assetObj.fun.push(resolve)
            if (assetObj.fun.length > 1) {
                return
            }
            // @ts-ignore
            cc.resources.load<T>(assetPath, type, (err, res: T) => {
                if (!err) {
                    assetObj.fun.forEach((fun) => {
                        res.addRef()
                        fun(res)
                        assetObj.lock -= 1
                    })
                    assetObj.fun = []
                } else {
                    // @ts-ignore
                    logMgr.error(`asset load error!!找不到资源,路径: ${assetPath} ${err.message}`)
                    resolve(null)
                }
            })
        });
    }

    public releaseByRecord(url: string, count: number) {
        let assetObj = this.cache.get(url)
        if (!assetObj) {
            logMgr.warn(`recordAssetRef is null [url:${url}]`)
            return
        }
        assetObj.decRef += count
    }

    public tryToRelease(): void {
        let self = this
        this.cache.forEach((assetObj, key) => {
            if (assetObj.lock <= 0) {
                let count = assetObj.decRef
                if (assetObj.asset.refCount < assetObj.decRef) {
                    logMgr.warn(`tryToRelease mult times ${key} refCount:${assetObj.asset.refCount} decRef:${assetObj.decRef}`)
                    count = assetObj.asset.refCount
                }
                assetObj.asset.refCount -= count
                if (assetObj.asset.refCount <= 0) {
                    cc.assetManager.releaseAsset(assetObj.asset)
                    assetObj.asset = null
                    self.cache.delete(key)
                    logMgr.log(`release asset ${key}`)
                }
            }
        })
    }
}

export let resMgr = ResMgr.getInstance()